<?php
/**
 * Created by PhpStorm.
 * User: chenpeixin
 * Date: 2016/11/14
 * Time: 15:06
 */

namespace App\Http\Middleware;

use App\Logging\Logger;
use Closure;
use Firebase\JWT\JWT;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;

use App\Exceptions\v1\Unauthorized;
use App\Exceptions\v1\Forbidden;

class ApiV1Standard
{
    // 误差时间 5 秒
    protected static $leeway = 5;

    public function handle(Request $request, Closure $next)
    {
        JWT::$leeway = self::$leeway;
        $appid = $request->header('X-APPID', null);
        $jwt = $request->header('X-JWT-Signature', null);
        $this->isAuthorized($appid, $jwt);
        $logId = $request->header('X-LOGID', null);
        $this->isLegalLogId($logId);
        $this->setLogLabel($logId);

        return $next($request);
    }

    /**
     * 判断是否有权限
     *
     * @param string $logId log id
     *
     * @throws Forbidden 无权限
     */
    protected function isLegalLogId($logId)
    {
        if ($logId === null) {
            throw new Forbidden('X-LOGID 为空');
        }
    }

    /**
     * 设置日志log id
     *
     * @param string $logId logid
     */
    protected function setLogLabel($logId)
    {
        Logger::setLogId($logId);
    }

    /**
     * 判断是否授权
     *
     * @param string $appid appid
     * @param string $jwt jwt
     *
     * @throws Unauthorized 未授权
     */
    protected function isAuthorized($appid, $jwt)
    {
        Logger::getLogger('validation')->debug('appid:' . $appid);
        Logger::getLogger('validation')->debug('jwt:' . $jwt);
        if ($appid === null) {
            throw new Unauthorized('X-APPID 为空');
        }
        if ($jwt === null) {
            throw new Unauthorized('X-JWT-Signature 为空');
        }
        if (empty(Config::get('token')[$appid])) {
            throw new Unauthorized('X-APPID 不合法，联系相关 RD');
        }
        $appsecret = Config::get('token')[$appid]['appsecret'];
        $expire = Config::get('token')[$appid]['expire'];

        try {
            $decode = JWT::decode($jwt, $appsecret, ['HS256']);
        } catch (\UnexpectedValueException $e) {
            throw new Unauthorized('JWT 不合法，联系相关 RD');
        }
        if (!isset($decode->iss)) {
            throw new Unauthorized('JWT 签名缺少 iss，应该是 X-APPID 值');
        }
        Logger::getLogger('validation')->debug('iss:' . var_export($decode->iss, true));
        if ($decode->iss !== $appid) {
            throw new Unauthorized('JWT 签名 iss 不等于 X-APPID');
        }

        if (!isset($decode->iat)) {
            throw new Unauthorized('JWT 签名缺少 iat，应该是请求时的时间戳');
        }
        Logger::getLogger('validation')->debug('iat:' . var_export($decode->iat, true));
        $now = time();
        Logger::getLogger('validation')->debug('now:' . $now);
        Logger::getLogger('validation')->debug('expire:' . var_export($expire, true));
        $requestTime = $decode->iat;
        if ($requestTime > ($now + self::$leeway)) {
            Logger::getLogger('validation')->debug('请求时间在当前时间之后，穿越了');
            throw new Unauthorized('请求时间在当前时间之后，看是不是时间不同步');
        }
        if ($expire !== false) {
            if ($requestTime < ($now - $expire - self::$leeway)) {
                Logger::getLogger('validation')->debug('请求时间过期了');
                throw new Unauthorized('请求已过期');
            }
        }
    }
}
